{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DemoStrategy\n",
    "\n",
    "## 视频中介绍了针对四只股票的等权重投资策略\n",
    "## 本段代码展示了利用quantOS系统进行策略回测及仿真交易的具体步骤。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 环境设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# -*- encoding: utf-8 -*-\n",
    "import time\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "from jaqs.data import DataApi\n",
    "\n",
    "from jaqs.data import RemoteDataService\n",
    "from jaqs.trade import AlphaBacktestInstance\n",
    "from jaqs.trade import PortfolioManager\n",
    "#from jaqs.trade import RealTimeTradeApi\n",
    "\n",
    "import jaqs.util as jutil\n",
    "import jaqs.trade.analyze as ana\n",
    "from jaqs.trade import AlphaStrategy\n",
    "from jaqs.trade import AlphaTradeApi\n",
    "from jaqs.trade import model\n",
    "from jaqs.data import DataView"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置文件存储路径\n",
    "dataview_dir_path = 'demoStrategy/dataview'\n",
    "backtest_result_dir_path = 'demoStrategy'\n",
    "\n",
    "# 设置服务器地址、用户名密码\n",
    "# 例如：\n",
    "# data_config = {\n",
    "#   \"remote.data.address\": \"tcp://data.quantos.org:8910\",\n",
    "#   \"remote.data.username\":  '18688888888',\n",
    "#   \"remote.data.password\":  '23sdjfk209d0fs9dejkl2j3k4j9d0fsdf'}\n",
    "\n",
    "# 如果没有使用quantos金融终端，请自行替换phone,token内容\n",
    "import os\n",
    "phone = os.environ.get(\"QUANTOS_USER\")\n",
    "token = os.environ.get(\"QUANTOS_TOKEN\")\n",
    "\n",
    "data_config = {\n",
    "  \"remote.data.address\": \"tcp://data.quantos.org:8910\",\n",
    "  \"remote.data.username\":  phone,\n",
    "  \"remote.data.password\":  token}\n",
    "trade_config = {\n",
    "  \"remote.trade.address\": \"tcp://gw.quantos.org:8901\",\n",
    "  \"remote.trade.username\":  phone,\n",
    "  \"remote.trade.password\":  token}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 修改自己的策略号（仿真交易使用）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置Strategy number, 根据自己的实际情况设置\n",
    "# 例如：StrategyNo = 1043\n",
    "StrategyNo = 1008"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 参数设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# -------------------------------------------------------------------------------\n",
    "# 设置目标股票、业绩基准、权重、时间\n",
    "# -------------------------------------------------------------------------------\n",
    "symbol_weights = {'600519.SH': 0.25,\n",
    "                  '600036.SH': 0.25,\n",
    "                  '601318.SH': 0.25,\n",
    "                  '000651.SZ': 0.25}\n",
    "\n",
    "benchmark = '000300.SH'\n",
    "\n",
    "my_symbols = ','.join(symbol_weights.keys())\n",
    "start_date = 20170201\n",
    "end_date = 20171001\n",
    "\n",
    "# 定义权重函数\n",
    "def stockWeight(context, user_options=None):\n",
    "    return pd.Series(symbol_weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. 回测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# -------------------------------------------------------------------------------\n",
    "# Main code 这个代码框不需要修改\n",
    "# -------------------------------------------------------------------------------\n",
    "\n",
    "def test_save_dataview():\n",
    "    ds = RemoteDataService()\n",
    "    ds.init_from_config(data_config)\n",
    "    dv = DataView()\n",
    "\n",
    "    props = {'start_date': start_date, 'end_date': end_date,\n",
    "             'fields': 'sw1',\n",
    "             'symbol': my_symbols,\n",
    "             'freq': 1}\n",
    "\n",
    "    dv.init_from_config(props, ds)\n",
    "    dv.prepare_data()\n",
    "\n",
    "    # set the benchmark\n",
    "    res, _ = ds.daily(benchmark, start_date=dv.start_date, end_date=dv.end_date)\n",
    "    dv._data_benchmark = res.set_index('trade_date').loc[:, ['close']]\n",
    "\n",
    "    dv.save_dataview(folder_path=dataview_dir_path)\n",
    "\n",
    "\n",
    "def test_alpha_strategy_dataview():\n",
    "    dv = DataView()\n",
    "\n",
    "    dv.load_dataview(folder_path=dataview_dir_path)\n",
    "\n",
    "    props = {\n",
    "        \"symbol\": dv.symbol,\n",
    "        \"universe\": ','.join(dv.symbol),\n",
    "\n",
    "        \"start_date\": dv.start_date,\n",
    "        \"end_date\": dv.end_date,\n",
    "\n",
    "        \"period\": \"week\",\n",
    "        \"days_delay\": 0,\n",
    "\n",
    "        \"init_balance\": 1e7,\n",
    "        \"position_ratio\": 1.0,\n",
    "        \"commission_rate\": 2E-4  # 手续费万2\n",
    "    }\n",
    "    props.update(data_config)\n",
    "    props.update(trade_config)\n",
    "\n",
    "    trade_api = AlphaTradeApi()\n",
    "\n",
    "    signal_model = model.FactorSignalModel()\n",
    "    signal_model.add_signal('stockWeight', stockWeight)\n",
    "\n",
    "    strategy = AlphaStrategy(signal_model=signal_model, pc_method='factor_value_weight')\n",
    "    pm = PortfolioManager()\n",
    "\n",
    "    bt = AlphaBacktestInstance()\n",
    "    \n",
    "    context = model.Context(dataview=dv, instance=bt, strategy=strategy, trade_api=trade_api, pm=pm)\n",
    "    \n",
    "    signal_model.register_context(context)\n",
    "\n",
    "    bt.init_from_config(props)\n",
    "\n",
    "    bt.run_alpha()\n",
    "\n",
    "    bt.save_results(folder_path=backtest_result_dir_path)\n",
    "    \n",
    "\n",
    "def test_backtest_analyze():\n",
    "    ta = ana.AlphaAnalyzer()\n",
    "    dv = DataView()\n",
    "    dv.load_dataview(folder_path=dataview_dir_path)\n",
    "\n",
    "    ta.initialize(dataview=dv, file_folder=backtest_result_dir_path)\n",
    "\n",
    "    ta.do_analyze(result_dir=backtest_result_dir_path, selected_sec=ta.universe,\n",
    "                  brinson_group=None)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 运行这里跑回测\n",
    "test_save_dataview()\n",
    "test_alpha_strategy_dataview()\n",
    "test_backtest_analyze()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "回测显示运行完成后，报告可从上面对话框最后一行的地址中找到 `HTML report: ...\\demoStrategy\\report.html`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. 仿真交易"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1 初始化交易API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from jaqs.trade.tradeapi import TradeApi\n",
    "\n",
    "tapi = TradeApi(trade_config['remote.trade.address'])\n",
    "\n",
    "user_info, msg = tapi.login(trade_config['remote.trade.username'], trade_config['remote.trade.password'])\n",
    "tapi.use_strategy(StrategyNo)  #改成用户自己的 strategy号\n",
    "\n",
    "res, msg = tapi.query_account()\n",
    "money = res.loc[0, 'enable_balance']\n",
    "print(\"Balance we have: {}\".format(money))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2 构造目标订单"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "data_api = DataApi(data_config['remote.data.address'])\n",
    "user_info, msg = data_api.login(phone, token)\n",
    "\n",
    "quotes, msg = data_api.quote('600519.SH,600036.SH,601318.SH,000651.SZ')\n",
    "\n",
    "dic_price      = {'600519.SH': quotes['last']['600519.SH'],\n",
    "                  '600036.SH': quotes['last']['600036.SH'],\n",
    "                  '601318.SH': quotes['last']['601318.SH'],\n",
    "                  '000651.SZ': quotes['last']['000651.SZ']}\n",
    "\n",
    "# 每只股票等金额投资，各买入30万元\n",
    "dic_shares = {k: 100 * np.floor(money * 0.012 * symbol_weights[k] / dic_price[k]/100) for k, _ in symbol_weights.items()}\n",
    "dic_shares\n",
    "\n",
    "orders = []\n",
    "for symbol in symbol_weights.keys():\n",
    "    o = {'security': symbol, 'price': dic_price[symbol], 'size': dic_shares[symbol], 'action': 'Buy'}\n",
    "    orders.append(o)\n",
    "orders"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.3 发送订单买入股票"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 买入股票\n",
    "task_id, msg = tapi.place_batch_order(orders)\n",
    "print(task_id)\n",
    "print(msg)    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.4 查询订单信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "orders, msg = tapi.query_order(task_id)\n",
    "orders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 做空一手沪深300股指期货做对冲\n",
    "# task_id, msg = tapi.place_order(\"IF1712.CFE\", \"Short\", 4003.6, 1)\n",
    "# print(task_id)\n",
    "# print(msg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
